package com.think.admin.oauth.permission.impl;

import com.think.admin.cons.AdminCons;
import com.think.admin.model.dto.role.RoleResourceDTO;
import com.think.admin.model.dto.user.UserRoleDto;
import com.think.admin.oauth.permission.PermissionService;
import com.think.admin.oauth.rbac.RbacUserDetails;
import com.think.admin.web.service.IResourceService;
import com.think.common.enums.StateEnum;
import com.think.common.utils.SysUtils;
import com.think.dao.entity.Resource;
import com.think.dao.enums.ResourcePermissionTypeEnum;
import com.think.dao.enums.ResourceTypeEnum;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RedissonClient;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 权限服务实现类
 * </p>
 *
 * @author: xwj
 * @data: 2019-05-13
 */
@Component("permissionService")
@RequiredArgsConstructor
public class PermissionServiceImpl implements PermissionService {
    private final IResourceService resourceService;
    private final RedissonClient redissonClient;

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        // 对象提取
        Object principal = authentication.getPrincipal();
        if (SysUtils.isEmpty(principal) || !(principal instanceof RbacUserDetails)) {
            return false;
        }

        // 参数提取
        String userId = ((RbacUserDetails) principal).getUserId();
        if (SysUtils.isEmpty(userId)) {
            return false;
        }

        // 超级管理员直接通行
        if (AdminCons.Param.SUPER_ADMIN_ID.equals(userId)) {
            return true;
        }

        // 校验
        RequestMatcher requestMatcher = this.getRequestMatcher(userId);
        if (SysUtils.isNotEmpty(requestMatcher) && requestMatcher.matches(request)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取权限判断对象
     *
     * @param userId
     * @return
     */
    private RequestMatcher getRequestMatcher(String userId) {
        // 容器
        List<RequestMatcher> requestMatcherList = new ArrayList<>();

        // 加载账号所拥有的权限表达式
        Map<String, UserRoleDto> userRoleMap = redissonClient.getMap(AdminCons.Redis.USER_ROLE + userId);
        if (SysUtils.isNotEmpty(userRoleMap)) {
            userRoleMap.keySet().forEach(key -> {
                Map<String, RoleResourceDTO> roleResource = redissonClient.getMap(AdminCons.Redis.ROLE_RESOURCE + key);
                if (SysUtils.isEmpty(roleResource)) {
                    return;
                }
                roleResource.values().forEach(rr -> {
                    if (SysUtils.isEmpty(rr) || SysUtils.isEmpty(rr.getPermission())) {
                        return;
                    }

                    // 解析权限表达式
                    String[] permissionArray = rr.getPermission().split(":");
                    if (SysUtils.isEmpty(permissionArray)) {
                        return;
                    }

                    // 提取参数
                    String methodType = permissionArray[0];
                    String permission = permissionArray[1];
                    if (SysUtils.isNull(methodType, permission)) {
                        return;
                    }

                    // 组装
                    requestMatcherList.add(new AntPathRequestMatcher("/" + permission, methodType));
                });
            });
        }

        // 加载只需登录资源的权限表达式
        resourceService.lambdaQuery()
                .select(Resource::getPermission)
                .eq(Resource::getState, StateEnum.ENABLE)
                .eq(Resource::getPermissionType, ResourcePermissionTypeEnum.LOGIN)
                .eq(Resource::getType, ResourceTypeEnum.RESOURCE).list().forEach(r -> {
            if (SysUtils.isEmpty(r) || SysUtils.isEmpty(r.getPermission())) {
                return;
            }

            // 解析权限表达式
            String[] permissionArray = r.getPermission().split(":");
            if (SysUtils.isEmpty(permissionArray)) {
                return;
            }

            // 提取参数
            String methodType = permissionArray[0];
            String permission = permissionArray[1];
            if (SysUtils.isNull(methodType, permission)) {
                return;
            }

            // 组装
            requestMatcherList.add(new AntPathRequestMatcher("/" + permission, methodType));
        });

        // 判断并返回
        if (SysUtils.isEmpty(requestMatcherList)) {
            return null;
        } else {
            return new OrRequestMatcher(requestMatcherList);
        }
    }
}
